

#include "GMK80Reader.h"


GMK80Reader::GMK80Reader(gameData* dataStructure) {
	this->dataContainer = dataStructure; //Set the structure that will store the game data
}

void GMK80Reader::log(const char* format, ...) { //Output a message
	if (verbose) {
		va_list args;
		va_start( args, format );
		vprintf(format, args);
		va_end( args );
	}
}

bool GMK80Reader::validateFile() { //Validates the file to make sure we can parse it.
	if (fileData->readDword()==GMK80MAGICNUMBER) { //If the file has the magic number for gmk80 file
		log("File appears to be valid GMK file.\n");
	}else{
		log("File does not appear to be a GMK file.\n");
		return false;
	}
	unsigned int gmkVersion = fileData->readDword(); //Read the version of the GMK
	if (gmkVersion==VERSIONPARSE) { //If the version of the gmk is valid
		log("Version is 8.0. Continuing parse. \n");
	}else{
		log("Version is not 8.0. Version is: %i\n",gmkVersion);
		return false;
	}
	return true;
}

PARSESTATUS GMK80Reader::parseData(dataStream* stream, bool verbose) { //Parse the specified stream.
	fileData = stream; //Set the stream we will be parsing
	this->verbose = verbose; //Set verbose?
	log("Beginning parse...\n");
	fileData->seekg(0,beg); //Seek to the beginning
	log("Validating file...\n");
	if (validateFile()== false) { //Check if the file is valid (aka, can we parse it?)
		return INVALID_FILE; //File was not valid, return error
	}
	dataContainer->gameID = fileData->readDword(); //Read the game ID
	log ("Read Game ID: %i\n", dataContainer->gameID);
	fileData->seekg(16,cur); //Jump past 16 bytes (purpose of these bytes is unclear)
	fileData->readDword(); //"GM Version needed for game settings", we don't actually care about this as we already know the file is GM8.
	log ("Reading Game Settings Data...\n");
	dataStream *gameSettings = fileData->readBytes(fileData->readDword()); //Create a datastream that consists of the zlib compressed Game Settings
	gameSettings->uncompressData(); //Decompress the gameSettings
	parseGameSettings(gameSettings);

	log ("Reading Triggers...\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int triggerCount = fileData->read<int>(); //Read number of triggers
	log ("%i Triggers will be parsed.\n",triggerCount);
	for (int i=0; i<triggerCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd trigger data
		rData->uncompressData(); //Decompress
		parseTrigger(rData);
	}
	this->dataContainer->triggersChanged = fileData->read<double>(); //Last time triggers were modified.


	log ("Reading Constants...\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int constantCount = fileData->read<int>(); //Number of constants
	log ("%i Constants will be parsed.\n",constantCount);
	for (int i=0; i<constantCount; i++) {
		constantDef *NC = new constantDef();
		NC->Name = fileData->readString(); //Read constant name
		NC->Value = fileData->readString(); //Read constant value
		this->dataContainer->Constants.push_back(NC); //Add the new constant to the list
	}
	this->dataContainer->constantsChanged = fileData->read<double>(); //Last time constants were modified.

	log ("Reading Resources [Sounds]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int soundCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Sounds will be parsed.\n",soundCount);
	for (int i=0; i<soundCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseSound(rData);
	}


	log ("Reading Resources [Sprites]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int spriteCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Sprites will be parsed.\n",spriteCount);
	for (int i=0; i<spriteCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseSprite(rData);
	}

	log ("Reading Resources [Backgrounds]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int bgCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Backgrounds will be parsed.\n",bgCount);
	for (int i=0; i<bgCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseBackground(rData);
	}

	log ("Reading Resources [Paths]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int pathCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Paths will be parsed.\n",pathCount);
	for (int i=0; i<pathCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parsePath(rData);
	}

	log ("Reading Resources [Scripts]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int scriptCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Scripts will be parsed.\n",scriptCount);
	for (int i=0; i<scriptCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseScript(rData);
	}

	log ("Reading Resources [Fonts]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int fontCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Fonts will be parsed.\n",fontCount);
	for (int i=0; i<fontCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseFont(rData);
	}

	log ("Reading Resources [Timelines]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int timelineCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Timelines will be parsed.\n",timelineCount);
	for (int i=0; i<timelineCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseTimeline(rData);
	}

	log ("Reading Resources [Objects]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int objectCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Objects will be parsed.\n",objectCount);
	for (int i=0; i<objectCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseObject(rData);
	}

	log ("Reading Resources [Rooms]..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int roomCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Rooms will be parsed.\n",roomCount);
	for (int i=0; i<roomCount; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseRoom(rData);
	}


	this->dataContainer->lastInstancePlaced = fileData->read<int>(); //The last instance placed
	this->dataContainer->lastTilePlaced = fileData->read<int>(); //The last tile placed

	log ("Reading Included data files..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int includedFiles = fileData->read<int>(); //Read the number of sprites
	log ("%i Included files will be parsed.\n",includedFiles);
	for (int i=0; i<includedFiles; i++) {
		dataStream *rData = fileData->readBytes(fileData->readDword()); //Read the zlib'd resource data
		rData->uncompressData(); //Decompress
		parseIncludedFile(rData);
	}

	log ("Reading Packages..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int packageCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Packages will be parsed.\n",packageCount);
	for (int i=0; i<packageCount; i++) {
		this->dataContainer->Packages.push_back(fileData->readString()); //Read the package name.
	}

	log ("Reading Game information..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	dataStream *gameInfo = fileData->readBytes(fileData->readDword()); //Read the zlib'd game info
	gameInfo->uncompressData(); //Decompress
	parseGameInformation(gameInfo);

	log ("Reading Library Information..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int libraryCount = fileData->read<int>(); //Read the number of sprites
	log ("%i Libraries will be parsed.\n",libraryCount );
	for (int i=0; i<libraryCount ; i++) {
		this->dataContainer->libCreationCodes.push_back(fileData->readString()); //Read library creation code
	}

	log ("Reading Room execution order..\n");
	fileData->readDword(); //GM Version needed for this resource. The file was already determined to be Version 8.0 so this is completely useless; discard it
	int roomOrderCount = fileData->read<int>(); //Read the number of sprites
	for (int i=0; i<roomOrderCount; i++) {
		this->dataContainer->roomExecutionOrder.push_back(fileData->read<int>()); //Read room ID
	}


	log ("Reading Tree structure..\n");
	for(int i=0; i<12; i++) {
		ResourceTreeDef * rootTree = new ResourceTreeDef();
		rootTree->Status = fileData->read<int>(); //Read the status (1 "Primary, 2 Group, 3 Secondary")
		rootTree->Group = fileData->read<int>(); //Read the group 
		rootTree->Index = fileData->read<int>(); //Read the index
		rootTree->Name = fileData->readString(); //Read the string
		int contentCount = fileData->read<int>(); //How many sub nodes this has
		RecursiveTreeAdd(rootTree, contentCount, fileData);
		this->dataContainer->ResourceTree.push_back(rootTree);
	}

	log ("Finished!");
	return SUCCESS;
}

PARSESTATUS GMK80Reader::parseData(std::string fileName, bool verbose) { //Overload, allows file name specification, and stream will be created automatically
	fileData = new dataStream();
	fileData->load(fileName); //Load the specified file
	return parseData(fileData, verbose);
}

void GMK80Reader::RecursiveTreeAdd(ResourceTreeDef* Node, int childrenCount, dataStream * data) {
	for(int i=0; i<childrenCount; i++) {
		ResourceTreeDef * newTree = new ResourceTreeDef();
		newTree->Status = data->read<int>(); //Read the status (1 "Primary, 2 Group, 3 Secondary")
		newTree->Group =data->read<int>(); //Read the group 
		newTree->Index = data->read<int>(); //Read the index
		newTree->Name = data->readString(); //Read the string
		int contentCount = data->read<int>(); //How many sub nodes this has
		RecursiveTreeAdd(newTree, contentCount, data);
		Node->Contents.push_back(newTree);
	}
}


void GMK80Reader::parseGameSettings(dataStream *data) {
	this->dataContainer->gameSettings.startInFullScreen = data->readBool4(); //Read full screen
	this->dataContainer->gameSettings.interpolateColors= data->readBool4(); 
	this->dataContainer->gameSettings.dontDrawBorder = data->readBool4(); 
	this->dataContainer->gameSettings.displayCursor = data->readBool4(); 
	this->dataContainer->gameSettings.Scaling = data->read<int>(); 
	this->dataContainer->gameSettings.allowWindowResize = data->readBool4(); 
	this->dataContainer->gameSettings.alwaysOnTop = data->readBool4(); 
	this->dataContainer->gameSettings.colorOutsideRoom = data->read<int>(); 
	this->dataContainer->gameSettings.setResolution = data->readBool4(); 
	this->dataContainer->gameSettings.colorDepth = data->read<int>(); 
	this->dataContainer->gameSettings.Resolution = data->read<int>();  
	this->dataContainer->gameSettings.Frequency= data->read<int>();  
	this->dataContainer->gameSettings.dontShowButtons = data->readBool4(); 
	this->dataContainer->gameSettings.useSync= data->readBool4(); 
	this->dataContainer->gameSettings.disableScreen = data->readBool4(); 
	this->dataContainer->gameSettings.letF4 = data->readBool4(); 
	this->dataContainer->gameSettings.letF1 = data->readBool4(); 
	this->dataContainer->gameSettings.letEsc = data->readBool4();
	this->dataContainer->gameSettings.letF5 = data->readBool4(); 
	this->dataContainer->gameSettings.letF9 = data->readBool4();
	this->dataContainer->gameSettings.treatCloseAsEsc = data->readBool4();
	this->dataContainer->gameSettings.processPriority = data->read<int>(); 
	this->dataContainer->gameSettings.freezeUnfocus = data->readBool4();
	this->dataContainer->gameSettings.loadingBar = data->read<int>(); 

	this->dataContainer->gameSettings.backImageData = NULL; //In case there is no data, we want it safely set to NULL
	this->dataContainer->gameSettings.frontImageData = NULL; //In case there is no data, we want it safely set to NULL
	if (this->dataContainer->gameSettings.loadingBar==2)
	{
		if (data->readBool4()==true)
		{//If loading bar back image data exists..
			this->dataContainer->gameSettings.backImageData = data->readBytes(data->readDword());
			this->dataContainer->gameSettings.backImageData->uncompressData();
		}
		if (data->readBool4()==true)
		{//If loading bar front image data exists..
			this->dataContainer->gameSettings.frontImageData = data->readBytes(data->readDword());
			this->dataContainer->gameSettings.frontImageData->uncompressData();
		}
	}
	this->dataContainer->gameSettings.customLoadImage = data->readBool4();
	this->dataContainer->gameSettings.loadBarImageData = NULL; //In case there is no data, we want it safely set to NULL
	if (this->dataContainer->gameSettings.customLoadImage==1)
	{
		if (data->readBool4()==true)
		{//If loading bar image exists
			this->dataContainer->gameSettings.loadBarImageData = data->readBytes(data->readDword());
			this->dataContainer->gameSettings.loadBarImageData->uncompressData();
		}
	}
	this->dataContainer->gameSettings.imageTransparent = data->readBool4();
	this->dataContainer->gameSettings.translucentAlpha = data->read<int>();
	this->dataContainer->gameSettings.scaleProgressBar = data->readBool4();
	//Read the icon data..
	int size = data->readDword();
	this->dataContainer->gameSettings.iconData = data->readBytes(size);
	this->dataContainer->gameSettings.displayErrors = data->readBool4();
	this->dataContainer->gameSettings.errorLog = data->readBool4();
	this->dataContainer->gameSettings.abortErrors = data->readBool4();
	this->dataContainer->gameSettings.unitializedVarsZero = data->readBool4();
	this->dataContainer->gameSettings.Author = data->readString();
	this->dataContainer->gameSettings.Version = data->readString();
	this->dataContainer->gameSettings.lastChanged = data->read<double>();
	this->dataContainer->gameSettings.Information = data->readString();
	this->dataContainer->gameSettings.majorVersion = data->read<int>();
	this->dataContainer->gameSettings.minorVersion = data->read<int>();
	this->dataContainer->gameSettings.releaseVersion = data->read<int>();
	this->dataContainer->gameSettings.buildVersion = data->read<int>();
	this->dataContainer->gameSettings.Company = data->readString();
	this->dataContainer->gameSettings.Product = data->readString();
	this->dataContainer->gameSettings.Copyright =data->readString();
	this->dataContainer->gameSettings.Description = data->readString();
	this->dataContainer->gameSettings.lastSettingsChange = data->read<double>();
}

void GMK80Reader::parseGameInformation(dataStream *data) {
	this->dataContainer->gameInformation.backgroundColor = data->read<int>(); //Read background color
	this->dataContainer->gameInformation.seperateWindow = data->read<int>(); //Read seperate window
	this->dataContainer->gameInformation.formCaption = data->read<int>(); //Read form caption
	this->dataContainer->gameInformation.positionLeft = data->read<int>(); //Left position
	this->dataContainer->gameInformation.positionTop = data->read<int>(); //Top position
	this->dataContainer->gameInformation.positionWidth = data->read<int>(); //Width
	this->dataContainer->gameInformation.positionHeight = data->read<int>(); //Height
	this->dataContainer->gameInformation.showWindowBorder = data->readBool4(); //Show border?
	this->dataContainer->gameInformation.allowResize = data->readBool4(); //Allow resize?
	this->dataContainer->gameInformation.stayOnTop = data->readBool4(); //Always stay on top
	this->dataContainer->gameInformation.stopGame = data->readBool4(); //Stop the game?
	this->dataContainer->gameInformation.lastChanged = data->read<double>(); //Last time changed
	this->dataContainer->gameInformation.gameInformationRTF = data->readString(); //RTF information (the actual contents)
}


void GMK80Reader::parseIncludedFile(dataStream *data) {
	includedFilesDef* newI = new includedFilesDef();
	newI->lastChanged = data->read<double>(); //Last time modified
	data->read<int>(); //Read past the "Gm version needed"
	newI->fileName = data->readString(); //Filename
	newI->filePath = data->readString(); //File path
	newI->originalFile = data->readBool4(); //Original file chosen?
	newI->originalFileSize = data->read<int>(); //Original File size
	newI->storedInGMK = data->readBool4(); //Stored in GMK?
	if (newI->storedInGMK==true) {
		newI->fileData = data->readBytes(data->readDword()); //read the file data
	}
	newI->exportType = data->read<int>(); //Type of export
	newI->folderExport = data->readString(); //folder to export
	newI->overWrite = data->readBool4(); //Overwrite?
	newI->freeMem = data->readBool4(); //Free memory ?
	newI->removeGameEnd = data->readBool4(); //Remove at game end?
	this->dataContainer->includedFiles.push_back(newI); //Add the included file
}
void GMK80Reader::parseTrigger(dataStream *data) {
	if (data->readBool4()==true) {//If the trigger exists
		triggerDef* newT = new triggerDef();
		data->read<int>(); //Read past the GM Version NEeded
		newT->Name = data->readString(); //Read trigger name
		newT->Condition = data->readString();; //Read consition as a string
		newT->checkMoment = data->read<int>(); //Moment of checking
		newT->constantName = data->readString();
		newT->exists = true; //It exists
		this->dataContainer->Triggers.push_back(newT); //Add the trigger
	}else{
		triggerDef* newT = new triggerDef();
		newT->exists = false; //Does not exist
		this->dataContainer->Triggers.push_back(newT); //Add the trigger
	}
}

void GMK80Reader::parseSound(dataStream *data) {
		if (data->readBool4()==true)
		{//If this sound exists
			soundDef* newSound = new soundDef();
			newSound->exists = true; //It exists
			newSound->Name = data->readString(); //Read the name
			newSound->lastChanged = data->read<double>(); //Read the last time it was changed
			data->read<int>(); //Skip the "GM version needed"
			newSound->Kind = data->read<int>(); //Kind of sound
			newSound->fileType = data->readString(); //Read the file tyoe
			newSound->fileName = data->readString(); //Read the file name
			newSound->musicData= NULL; //Set to null in case there is no music data
			if (data->readBool4()==true)
			{//If the music data exists
				newSound->musicData = data->readBytes(data->readDword()); //Read the sound data.
			}
			newSound->Effects = data->read<int>(); //Effects
			newSound->volume = data->read<double>(); //Volume
			newSound->Pan = data->read<double>(); //Pan
			newSound->preload = data->readBool4(); //PReload?
			this->dataContainer->Sounds.push_back(newSound);
		}else{
			soundDef* newSound = new soundDef();
			newSound->exists = false; //doest no exist
			this->dataContainer->Sounds.push_back(newSound);
		}
}

void GMK80Reader::parseSprite(dataStream *data) {
	if (data->readBool4()==true) {//If this sprite exists..
			spriteDef* newSprite = new spriteDef; //Create a new sprite
			newSprite->exists = true; //Resource exists
			newSprite->Name = data->readString(); //Set the sprite name
			newSprite->lastChanged = data->read<double>(); //Last time it was changed..
			data->read<int>(); //Read past "which version of GM is needed.."
			newSprite->originX = data->read<int>(); //Read x origin
			newSprite->originY = data->read<int>(); //Read y origin
			int subImages = data->read<int>();
			for(int i=0; i<subImages; i++) {//For each subImage
				subImageDef* newSubImage = new subImageDef();
				data->read<int>(); //Read past the "Which version of GM is needed..."
				newSubImage->Width = data->read<int>();
				newSubImage->Height = data->read<int>();
				if (newSubImage->Width!=0 && newSubImage->Width!=0) {//Read the image data...
					newSubImage->imageData = data->readBytes(data->readDword()); //read the image data
				}
				newSprite->subImages.push_back(newSubImage); //Add the new subimage
			}
			newSprite->shape = data->read<int>(); //Read the shape
			newSprite->alphaTolerance = data->read<int>(); //Read the alpa tolerance
			newSprite->seperateCollisionMasks = data->readBool4(); //Read a bool..
			newSprite->boundingBox = data->read<int>(); //Read the type of bounding box
			newSprite->Left = data->read<int>(); //Read left bounring box
			newSprite->Right = data->read<int>(); //Read right bounfing box
			newSprite->Bottom = data->read<int>(); //Read bottom bounting box
			newSprite->Top = data->read<int>();//Read top bounding box (yay I spelt bounding right finally!)
			this->dataContainer->Sprites.push_back(newSprite); //Add the sprite
	}else{
		spriteDef* newSprite = new spriteDef; //Create a new sprite
		newSprite->exists = false; //Resource exists
		this->dataContainer->Sprites.push_back(newSprite); //Add the sprite
	}
}

void GMK80Reader::parseBackground(dataStream *data) {
	if (data->readBool4()==true) {///If this background exists..
		backgroundDef* newBG = new backgroundDef();
		newBG->exists = true; //Resource Exists
		newBG->Name = data->readString(); //Read the name
		newBG->lastChanged = data->read<double>();
		data->read<int>(); //Read past the "GM version needed"
		newBG->tileSet = data->readBool4(); //Use as tile set?
		newBG->tileWidth = data->read<int>(); //Read tile width
		newBG->tileHeight = data->read<int>(); //Read tile height
		newBG->hOffset = data->read<int>(); //Read horizontal offset
		newBG->vOffset = data->read<int>(); //Read vertical offset
		newBG->hSep = data->read<int>(); //Read h. seperation
		newBG->vSep = data->read<int>(); //Read v. seperation
		data->read<int>(); //Read past another "GM version needed.."
		newBG->Width = data->read<int>(); //Read width
		newBG->Height = data->read<int>(); //Read height
		if (newBG->Width!=0 && newBG->Height!=0) {
			newBG->imageData = data->readBytes(data->readDword()); //Read the background data

		}
		this->dataContainer->Backgrounds.push_back(newBG);
	}else{
		backgroundDef* newBG = new backgroundDef();
		newBG->exists = false; //Resource does not exist
		this->dataContainer->Backgrounds.push_back(newBG);
	}
}

void GMK80Reader::parsePath(dataStream *data) {
	if (data->readBool4()==true) {
		pathDef* newP = new pathDef();
		newP->exists = true; //Resource Exists
		newP->Name = data->readString(); //Read the string
		newP->lastChanged = data->read<double>(); //LAst changed
		data->read<int>(); //read past the "GM version needed"
		newP->Kind = data->read<int>(); //connection Kind
		newP->Closed = data->readBool4(); //Is it closed?
		newP->Precision = data->read<int>(); //PRecision
		newP->roomIndexBG = data->read<int>(); //Room index
		newP->snapX = data->read<int>(); //Snap X
		newP->snapY = data->read<int>(); //Snap Y
		int numPoints = data->read<int>(); //How many points there are
		for(int i =0; i<numPoints; i++) {
			pathPointsDef* PDef = new pathPointsDef();
			PDef->x = data->read<double>(); //Read x position
			PDef->y = data->read<double>(); //Read y positon
			PDef->speed = data->read<double>(); //Read speed
			newP->Points.push_back(PDef);
		}
		this->dataContainer->Paths.push_back(newP); //Add the path to the list
	}else{
		pathDef* newP = new pathDef();
		newP->exists = false; //Resource does not exist
		this->dataContainer->Paths.push_back(newP); //Add the path to the list
	}
}

void GMK80Reader::parseScript(dataStream *data) {
	if (data->readBool4()==true) {//If this script ID exists..
		scriptDef* newScript = new scriptDef();
		newScript->Name = data->readString();  //Read the name of the script
		newScript->lastChanged = data->read<double>(); //Last time the script was changed
		data->read<int>(); //GM Version needed..
		newScript->Script = data->readString(); //Read the script text
		newScript->exists = true; //Exists
		this->dataContainer->Scripts.push_back(newScript);
	}else{
		scriptDef* newScript = new scriptDef();
		newScript->exists = false; //Does not exist
		this->dataContainer->Scripts.push_back(newScript);
	}
}

void GMK80Reader::parseFont(dataStream *data) {
	if (data->readBool4()==true) {//If the font exists
		fontDef* newF = new fontDef();
		newF->Name =  data->readString(); //Read name
		newF->exists = true; //Exists
		newF->lastChanged = data->read<double>(); //Read last changed
		data->read<int>(); //Read past the "version required"
		newF->fontName =  data->readString(); //Read the name of the font
		newF->Size = data->read<int>(); //Read the size
		newF->Bold = data->readBool4(); //is it bold?
		newF->Italic = data->readBool4(); //Is it italic?
		newF->charRangeBegin = data->read<int>(); //Range begin..
		newF->charRangeEnd = data->read<int>(); //Range end
		this->dataContainer->Fonts.push_back(newF); //Add the font to the list
	}else{
		fontDef* newF = new fontDef();
		newF->exists = false; //Does not exist
		this->dataContainer->Fonts.push_back(newF); //Add the font to the list
	}
}

void GMK80Reader::parseTimeline(dataStream *data) {
		if (data->readBool4()==true) {//If this timeline exists
			timelineDef* newT = new timelineDef();
			newT->TimelineName = data->readString(); //Read the name of the timeline
			newT->exists = true; //Exists
			newT->lastChanged = data->read<double>(); //LAst time changed
			data->read<int>(); //Read past the "Gm Version needed for this info
			int momentCount = data->read<int>(); //Read how many moments their are.
			for (int i=0; i<momentCount; i++) {//For each moment..
				timeLineMomentDef* newM = new timeLineMomentDef();
				newM->moment = data->read<int>(); //Read the moment position
				//Read the actions. This Portion is INDENTICAL to the portion of the object parser that parses actions..
				data->read<int>(); //Read past the "GM version needed" junk
					int actionCount = data->read<int>(); //How many actions the event has
					for (int j=0; j<actionCount; j++) {//For each action
						objectActionDef* newA = new objectActionDef();
						data->read<int>(); //Read past the "GM Version needed" 
						newA->libraryID = data->read<int>(); //Read the library ID
						newA->ID = data->read<int>(); //Read the action's ID
						newA->Kind = data->read<int>(); //The kind of action
						newA->maybeRelative = data->readBool4(); //this may be relative?
						newA->Question = data->readBool4(); //Is this a question
						newA->appliesToSomething = data->readBool4(); //Can this action apply to something?
						newA->Type = data->read<int>(); //Type of action
						newA->functionName = data->readString(); //Read function name
						newA->functionCode = data->readString(); //Function code
						newA->argumentsUsed = data->read<int>(); //How many arguments there were
						int argumentCount = data->read<int>(); //How many available arguments
						for (int ak=0; ak<argumentCount; ak++) {
							newA->argumentKind[ak] = data->read<int>(); //Read the kind of argument
						}
						newA->appliesToObject = data->read<int>(); //Which object this applies to
						newA->isRelative = data->readBool4(); //Is this relative?
						argumentCount = data->read<int>(); //How many available arguments
						for (int al=0; al<argumentCount; al++) {
							newA->argumentValues[al] = data->readString(); //Read the kind of argument
						}
						newM->actionsList.push_back(newA); //Add the action.
						data->read<int>(); //Read the -1 that marks the end of the action
					}//For each action

					newT->momentList.push_back(newM); //Add the new moment
			}//For each moment in the timeline
			this->dataContainer->Timelines.push_back(newT); //Add the new timeline 
		}else{//If this timeline exists
			timelineDef* newT = new timelineDef();
			newT->exists = false; //Does not exist
			this->dataContainer->Timelines.push_back(newT); //Add the new timeline 
		}
}

void GMK80Reader::parseObject(dataStream *data) {
	if (data->readBool4()==true) {//If this object exists
		objectDef* newO = new objectDef();
		newO->exists = true; //Exists
		newO->Name = data->readString(); //Name of object
		newO->lastChanged = data->read<double>(); //Last changed
		data->read<int>(); //Read past the "Gm version needed..."
		newO->spriteIndex = data->read<int>(); //Sprite index
		newO->Solid = data->readBool4(); //Read solid
		newO->Visible = data->readBool4(); //Visible?
		newO->Depth = data->read<int>(); //Read depth
		newO->Persistent = data->readBool4(); //Persistent?
		newO->parentObject = data->read<int>(); //Parent object Index
		newO->maskSpriteIndex = data->read<int>(); //Sprite Index of mask
		int I = data->read<int>(); //How many event types there are
		//Read all the events!
		for(int i=0; i<I+1; i++)
		{//For each event
			int eventNumb = data->read<int>();
			while (eventNumb!=-1)
			{
				objectEventDef* newE = new objectEventDef();
				newE->eventType = i; //Set the type of event
				newE->eventKind = eventNumb; //Read the event numb
				data->read<int>(); //Read past the "GM version needed" junk
				int actionCount = data->read<int>(); //How many actions the event has
				for (int j=0; j<actionCount; j++)
				{
					objectActionDef* newA = new objectActionDef();
					data->read<int>(); //Read past the "GM Version needed" 
					newA->libraryID = data->read<int>(); //Read the library ID
					newA->ID = data->read<int>(); //Read the action's ID
					newA->Kind = data->read<int>(); //The kind of action
					newA->maybeRelative = data->readBool4(); //this may be relative?
					newA->Question = data->readBool4(); //Is this a question
					newA->appliesToSomething = data->readBool4(); //Can this action apply to something?
					newA->Type = data->read<int>(); //Type of action
					newA->functionName = data->readString(); //Read function name
					newA->functionCode = data->readString(); //Function code
					newA->argumentsUsed = data->read<int>(); //How many arguments there were
					int argumentCount = data->read<int>(); //How many available arguments
					for (int ak=0; ak<argumentCount; ak++)
					{
						newA->argumentKind[ak] = data->read<int>(); //Read the kind of argument
					}
					newA->appliesToObject = data->read<int>(); //Which object this applies to
					newA->isRelative = data->readBool4(); //Is this relative?
					argumentCount = data->read<int>(); //How many available arguments
					for (int al=0; al<argumentCount; al++)
					{
						newA->argumentValues[al] = data->readString(); //Read the kind of argument
					}
					newE->Actions.push_back(newA); //Add the action
					data->read<int>(); //Read the -1 that marks the end of the action
				}
				newO->Events.push_back(newE); //Add the event
				eventNumb = data->read<int>();
			}
			continue; 
		}
		this->dataContainer->Objects.push_back(newO);
	}else{
		objectDef* newO = new objectDef();
		newO->exists = false; //Exists
		this->dataContainer->Objects.push_back(newO);
	}
}

void GMK80Reader::parseRoom(dataStream *data) {
	if (data->readBool4()==true) { //If the room exists
			roomDef* newR= new roomDef();
			newR->exists = true; //Exists
			newR->Name = data->readString(); //Read room name
			newR->lastChanged = data->read<double>(); //Read last changed data
			data->read<int>(); //Read past the "What gm version is needed"
			newR->roomCaption = data->readString(); //Read the room caption
			newR->Width = data->read<int>(); //Read the room width
			newR->Height = data->read<int>(); //Read the room height
			newR->snapX = data->read<int>(); //Read the snap x
			newR->snapY = data->read<int>(); //Read the snap y
			newR->isometricGrid = data->readBool4(); //Read isometric grid as a bool
			newR->Speed = data->read<int>();//Read the speed
			newR->Persistent = data->readBool4(); //Read if the room is persistent
			newR->backgroundColor = data->read<int>(); //Read the BG color
			newR->drawBackgroundColor = data->readBool4(); //Draw the background color?
			newR->creationCode = data->readString(); //Read room creation code
			int BGcount = data->read<int>(); //How many backgrounds in the room
			for (int i=0; i<BGcount; i++) {
				roomBGDef* newBG = new roomBGDef();
				newBG->Visible = data->readBool4(); //Visible when room starts?
				newBG->foregroundImage = data->readBool4(); //Show a forground image?
				newBG->backgroundIndex = data->read<int>(); //Background index
				newBG->X = data->read<int>(); //X position
				newBG->Y = data->read<int>(); // Y position
				newBG->tileH = data->readBool4(); //tile hor.?
				newBG->tileV = data->readBool4(); //tile v.?
				newBG->hSpeed = data->read<int>(); //H speed
				newBG->vSpeed = data->read<int>(); //V speed
				newBG->Stretch = data->readBool4(); //Stretch BG?
				newR->Backgrounds.push_back(newBG); //Add the background
			}
			newR->enableViews = data->readBool4(); //Enable views?
			int ViewCount = data->read<int>(); //Number of views
			for (int i=0; i<ViewCount; i++) {
				roomViewsDef* newV = new roomViewsDef();
				newV->visibleStart = data->readBool4(); //Visible when room starts?
				newV->viewX = data->read<int>(); // X position in the room
				newV->viewY = data->read<int>(); //Y position in the room
				newV->viewW = data->read<int>(); //View width
				newV->viewH = data->read<int>(); //view hwight
				newV->portX = data->read<int>(); //Post X
				newV->portY = data->read<int>(); //Port Y
				newV->portW = data->read<int>(); //Port width
				newV->portH = data->read<int>(); //port height
				newV->hBorder = data->read<int>(); //H border
				newV->vBorder = data->read<int>(); // V border
				newV->Hsp = data->read<int>(); //H speed
				newV->Vsp = data->read<int>(); //V speed
				newV->objFollow = data->read<int>(); //Object to follow
				newR->Views.push_back(newV); //Add the view
			}
			int instCount = data->read<int>(); //How many instances are in the room
			for(int i=0; i<instCount; i++) {
				roomInstancesDef* newI = new roomInstancesDef();
				newI->X = data->read<int>(); //x position
				newI->Y = data->read<int>(); //Y position
				newI->objectIndex = data->read<int>(); //Object index
				newI->ID = data->read<int>(); //Instance ID..
				newI->creationCode = data->readString(); //Instance creation code
				newI->Locked = data->readBool4(); //locked?
				newR->Instances.push_back(newI); //Add the instance
			}

			int tileCount = data->read<int>(); //Number of tiles
			for(int i=0; i<tileCount; i++) {
				roomTilesDef* newT = new roomTilesDef();
				newT->X = data->read<int>(); //Read x position
				newT->Y = data->read<int>(); // y position
				newT->backgroundIndex = data->read<int>(); //Background position
				newT->tileX = data->read<int>(); //Tille X position on background
				newT->tileY = data->read<int>(); //Tile y position on background
				newT->Width = data->read<int>(); //Width on BG
				newT->Height = data->read<int>(); //height on BG
				newT->Depth = data->read<int>(); //Depth/Layer
				newT->ID = data->read<int>(); //Tile ID
				newT->Locked = data->readBool4(); //Is it locked?
				newR->Tiles.push_back(newT); //Add the new tile
			}
			newR->rememberRoomEditorInfo = data->readBool4(); //remember room editor info?
			newR->roomEditorWidth = data->read<int>(); //Editor width
			newR->roomEditorHeight = data->read<int>(); //Editor height
			newR->showGrid = data->readBool4(); //Shw grid?
			newR->showObjects = data->readBool4(); //Show obhects?
			newR->showTiles = data->readBool4(); //Show tiles?
			newR->showBackgrounds = data->readBool4(); //Show bg's?
			newR->showForegrounds = data->readBool4(); //Show Foregrounds?
			newR->showViews = data->readBool4(); //Show views?
			newR->deleteUnderlyingObjects = data->readBool4(); //Delete underlyign objectS?
			newR->deleteUnderlyingTiles = data->readBool4(); //Delet underlying iles
			newR->Tab = data->read<int>(); //Tab that is focused
			newR->xPosScrollBar = data->read<int>(); //X position of h. scroll bar
			newR->yPosScrollBar = data->read<int>(); //Y pos of v scroll bar.
			this->dataContainer->Rooms.push_back(newR); //Add the new room

	}else{ //Does not exist
		roomDef* newR= new roomDef();
		newR->exists = false; //Exists
		this->dataContainer->Rooms.push_back(newR); //Add the new room
	}
}
